{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {
    "pycharm": {
     "name": "#%% md\n"
    }
   },
   "source": [
    "# Exponentiation and Hamiltonian Simulation\n",
    "\n",
    "This tutorial demonstrates how to use the Classiq platform exponentiation function to solve Hamiltonian simulation problems, thereby demonstrating the strength of the Classiq exponentiation module."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "pycharm": {
     "name": "#%% md\n"
    }
   },
   "source": [
    "## 1. Chemical Simulation\n",
    "\n",
    "Chemical simulation is one of the most exciting applications for quantum computers. When precise simulations of electron-electron interactions are necessary, it is sometimes possible to use a classical computer, but classical computers struggle to simulate more complex molecular interactions. It is best to simulate these particle interactions at the quantum level, and an excellent way to do this is with a quantum computer.\n",
    "\n",
    "The ability to accurately simulate molecular interactions will have extensive applications. When used for drug discovery, it will allow for the rapid development of vaccines and new cures for diseases. In materials research, we can hope to discover materials with higher strength-to-weight ratios and environmentally friendly building materials."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "pycharm": {
     "name": "#%% md\n"
    }
   },
   "source": [
    "## 2. The H<sub>2</sub>O Hamiltonian Simulation Problem\n",
    "\n",
    "Generate a circuit that approximates the unitary $e^{-iH}$ where $H$ is the qubit Hamiltonian of a H<sub>2</sub>O (water) molecule. The H<sub>2</sub>O Hamiltonian is composed of 551 Pauli strings on twelve qubits."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 1,
   "metadata": {
    "execution": {
     "iopub.execute_input": "2024-05-07T14:25:17.898382Z",
     "iopub.status.busy": "2024-05-07T14:25:17.897771Z",
     "iopub.status.idle": "2024-05-07T14:25:24.265267Z",
     "shell.execute_reply": "2024-05-07T14:25:24.264406Z"
    },
    "pycharm": {
     "name": "#%%\n"
    },
    "tags": []
   },
   "outputs": [],
   "source": [
    "from typing import cast\n",
    "\n",
    "from classiq import Pauli, PauliTerm\n",
    "from classiq.applications.chemistry import Molecule, MoleculeProblem\n",
    "\n",
    "CHAR_TO_STUCT_DICT = {\"I\": Pauli.I, \"X\": Pauli.X, \"Y\": Pauli.Y, \"Z\": Pauli.Z}\n",
    "\n",
    "\n",
    "def pauli_str_to_enums(pauli):\n",
    "    return [CHAR_TO_STUCT_DICT[s] for s in pauli]\n",
    "\n",
    "\n",
    "def pauli_list_to_hamiltonian(pauli_list):\n",
    "    return [\n",
    "        PauliTerm(\n",
    "            pauli=pauli_str_to_enums(pauli), coefficient=cast(complex, coeff).real\n",
    "        )\n",
    "        for pauli, coeff in pauli_list\n",
    "    ]\n",
    "\n",
    "\n",
    "molecule_H2O = Molecule(\n",
    "    atoms=[(\"O\", (0.0, 0.0, 0.0)), (\"H\", (0, 0.586, 0.757)), (\"H\", (0, 0.586, -0.757))]\n",
    ")\n",
    "\n",
    "gs_problem = MoleculeProblem(\n",
    "    molecule=molecule_H2O,\n",
    "    basis=\"sto3g\",\n",
    "    mapping=\"jordan_wigner\",\n",
    "    z2_symmetries=False,\n",
    "    freeze_core=True,\n",
    ")\n",
    "\n",
    "hamiltonian = pauli_list_to_hamiltonian(gs_problem.generate_hamiltonian().pauli_list)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "metadata": {
    "execution": {
     "iopub.execute_input": "2024-05-07T14:25:24.270675Z",
     "iopub.status.busy": "2024-05-07T14:25:24.269185Z",
     "iopub.status.idle": "2024-05-07T14:25:44.511070Z",
     "shell.execute_reply": "2024-05-07T14:25:44.510282Z"
    },
    "pycharm": {
     "name": "#%%\n"
    },
    "tags": []
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Classiq's exponentiation depth is 2307\n",
      "Classiq's exponentiation CX-count is 2598\n",
      "Opening: https://platform.classiq.io/circuit/246676e4-7b83-4354-b62e-75a981e26cd4?version=0.41.0.dev39%2B79c8fd0855\n"
     ]
    }
   ],
   "source": [
    "from classiq import (\n",
    "    CustomHardwareSettings,\n",
    "    Preferences,\n",
    "    QArray,\n",
    "    QuantumProgram,\n",
    "    allocate,\n",
    "    create_model,\n",
    "    qfunc,\n",
    "    set_preferences,\n",
    "    show,\n",
    "    suzuki_trotter,\n",
    "    synthesize,\n",
    "    write_qmod,\n",
    ")\n",
    "\n",
    "\n",
    "@qfunc\n",
    "def main() -> None:\n",
    "    state = QArray(\"state\")\n",
    "    allocate(len(hamiltonian[0].pauli), state)\n",
    "    suzuki_trotter(\n",
    "        hamiltonian,\n",
    "        evolution_coefficient=1,\n",
    "        order=1,\n",
    "        repetitions=1,\n",
    "        qbv=state,\n",
    "    )\n",
    "\n",
    "\n",
    "qmod = create_model(main)\n",
    "qmod = set_preferences(\n",
    "    qmod,\n",
    "    preferences=Preferences(\n",
    "        custom_hardware_settings=CustomHardwareSettings(basis_gates=[\"cx\", \"u\"])\n",
    "    ),\n",
    ")\n",
    "write_qmod(qmod, \"exponentiation\")\n",
    "\n",
    "qprog = synthesize(qmod)\n",
    "circuit = QuantumProgram.from_qprog(qprog)\n",
    "\n",
    "print(f\"Classiq's exponentiation depth is {circuit.transpiled_circuit.depth}\")\n",
    "print(\n",
    "    f\"Classiq's exponentiation CX-count is {circuit.transpiled_circuit.count_ops['cx']}\"\n",
    ")\n",
    "show(qprog)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "pycharm": {
     "name": "#%% md\n"
    }
   },
   "source": [
    "These impressive results can be compared to the naive exponentiation modules often found in the literature, see comprehensive comparison in the  [Hamiltonian Evolution](https://github.com/Classiq/classiq-library/blob/main/tutorials/technology_demonstrations/hamiltonian_evolution/hamiltonian_evolution.ipynb) notebook under [Technology Demonstrations](\"https://docs.classiq.io/latest/tutorials/tutorials/technology-demonstrations/) section."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "pycharm": {
     "name": "#%% md\n"
    }
   },
   "source": [
    "## 3. Automatic Error Reduction\n",
    "\n",
    "The Classiq exponentiation module provides error management, automatically minimizes the error, and determines the best Trotter-Suzuki order and repetitions for any provided depth. Try this with an arbitrarily input Pauli list on eight qubits."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "metadata": {
    "execution": {
     "iopub.execute_input": "2024-05-07T14:25:44.565253Z",
     "iopub.status.busy": "2024-05-07T14:25:44.564167Z",
     "iopub.status.idle": "2024-05-07T14:25:46.801933Z",
     "shell.execute_reply": "2024-05-07T14:25:46.801098Z"
    },
    "pycharm": {
     "is_executing": true,
     "name": "#%%\n"
    },
    "tags": []
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Opening: https://platform.classiq.io/circuit/1670a54e-03cb-4726-87c9-5b86c793f505?version=0.41.0.dev39%2B79c8fd0855\n"
     ]
    }
   ],
   "source": [
    "from classiq import exponentiation_with_depth_constraint\n",
    "\n",
    "pauli_list = [\n",
    "    (\"IIZXXXII\", 0.1),\n",
    "    (\"IIXXYYII\", 0.2),\n",
    "    (\"IIIIZZYX\", 0.3),\n",
    "    (\"XZIIIIIX\", 0.4),\n",
    "    (\"IIIIIZXI\", 0.5),\n",
    "    (\"IIIIIIZY\", 0.6),\n",
    "    (\"IIIIIIXY\", 0.7),\n",
    "    (\"IIYXYZII\", 0.8),\n",
    "    (\"IIIIIIXZ\", 0.9),\n",
    "    (\"IIYZYIII\", 1.0),\n",
    "]\n",
    "\n",
    "\n",
    "@qfunc\n",
    "def main() -> None:\n",
    "    state = QArray(\"state\")\n",
    "    allocate(len(pauli_list[0][0]), state)\n",
    "    exponentiation_with_depth_constraint(\n",
    "        pauli_list_to_hamiltonian(pauli_list),\n",
    "        evolution_coefficient=0.05,\n",
    "        max_depth=400,\n",
    "        qbv=state,\n",
    "    )\n",
    "\n",
    "\n",
    "qmod = create_model(main)\n",
    "\n",
    "\n",
    "write_qmod(qmod, \"exponentiation_minimize_error\")\n",
    "\n",
    "qprog = synthesize(qmod)\n",
    "show(qprog)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "pycharm": {
     "name": "#%% md\n"
    }
   },
   "source": [
    "The Classiq engine automatically opts for six second-order Suzuki-Trotter layers instead of 12 first-order layers, to minimize the error of the exponentiation within the depth constraints."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "pycharm": {
     "name": "#%% md\n"
    }
   },
   "source": [
    "## 4. Conclusion\n",
    "\n",
    "Classiq packages the domain expertise of dozens of scientists and quantum software engineers into the software platform. The result: a system that can automatically generate efficient quantum circuits for complex problems, making it faster and easier than ever to solve real-life problems with quantum computing. When the circuits are of manageable size, Classiq creates solutions that are on par with the best manually created circuits. When the circuits are larger than those a human can reasonably create, Classiq allows you to progress farther because of its powerful capabilities.\n"
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3 (ipykernel)",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.11.9"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 4
}
